package util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import messages.Message;

public class Network {
	
	public static void sendBytes(Socket s, byte[] bytes) throws IOException {
		DataOutputStream dos = new DataOutputStream(s.getOutputStream());
		dos.writeInt(bytes.length);
		dos.write(bytes);
		dos.flush();
	}

	public static byte[] readBytes(Socket socket) throws IOException {
		DataInputStream dis = new DataInputStream(socket.getInputStream());
		while(dis.available() < 4) { //badness
			try {
				Thread.sleep(1);
			} catch (Exception e) {}
		}
		int len = dis.readInt();
		while(dis.available() < len) { //badness
			try {
				Thread.sleep(1);
			} catch (Exception e) {}
		}
		byte[] bytes = new byte[len];
		dis.read(bytes);
		//System.out.println("Recv'd " + new String(bytes));
		return bytes;
	}
	
	public static byte[] serialize(Object o) throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(o);
		oos.flush();
		oos.close();
		return bos.toByteArray();
	}

	public static Message unserialize(byte[] bytes) throws IOException, ClassNotFoundException {
		ByteArrayInputStream arraystream = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = new ObjectInputStream(arraystream);
		Message recvd = (Message) ois.readObject();
		return recvd;
	}

	//ECB is questionable but since encrypt/decrypt are stateless can't pass CBC IV
	public static byte[] encrypt(SecretKey key, byte[] serialized) {
		try {		
			SecretKeySpec skeyspec = new SecretKeySpec(key.getEncoded(), "AES");
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
			byte[] result = cipher.doFinal(serialized);
			return result;			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static byte[] decrypt(SecretKey key, byte[] bytesrcvd) {
		try {		
			SecretKeySpec skeyspec = new SecretKeySpec(key.getEncoded(), "AES");
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, skeyspec);
			byte[] result = cipher.doFinal(bytesrcvd);
			return result;			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
}
